package service

import (
	"smart-flow/monitor/config"
	"smart-flow/monitor/logger"
	"sync"
	"time"

	"go.uber.org/zap"

	cmap "github.com/orcaman/concurrent-map"
)

type Session struct {
	timestamp int64
	uid       string
	bandwidth uint64
}

type Sessions struct {
	sessionsV4 cmap.ConcurrentMap
	sessionsV6 cmap.ConcurrentMap
}

var (
	sessionsOnce sync.Once
	sessionsIns  *Sessions
)

func SessionsInstance() *Sessions {
	sessionsOnce.Do(func() {
		sessionsIns = &Sessions{
			sessionsV4: cmap.New(),
			sessionsV6: cmap.New(),
		}
	})
	return sessionsIns
}

func (e *Sessions) AddV4Session(uid string, bandwidth int64) {
	e.sessionsV4.Set(uid, &Session{
		uid:       uid,
		timestamp: time.Now().Unix(),
		bandwidth: uint64(bandwidth),
	})
}

func (e *Sessions) UpdateV4Session(uid string) {
	session := e.GetV4Session(uid)
	if session == nil {
		return
	}
	session.timestamp = time.Now().Unix()
}

func (e *Sessions) GetV4Session(uid string) *Session {
	val, exist := e.sessionsV4.Get(uid)
	if !exist {
		return nil
	}
	return val.(*Session)
}

func (e *Sessions) DelV4Session(uid string) {
	e.sessionsV4.Remove(uid)
}

func (e *Sessions) ExistV4Session(uid string) bool {
	return e.sessionsV4.Has(uid)
}

func (e *Sessions) GetOnlineV4Stat() (int64, uint64, []string) {
	var (
		count        int64
		bandwidth    uint64
		expired      []string
		expiredCount int
	)
	now := time.Now().Unix()
	e.sessionsV4.IterCb(func(key string, value any) {
		session := value.(*Session)
		if now-session.timestamp < config.AppConfig().Dy.AgentInterval+60 {
			count++
			bandwidth += session.bandwidth
		} else {
			if expiredCount < config.AppConfig().Dy.ExpiredLimit {
				expired = append(expired, key)
			}
			expiredCount++
		}
	})
	for _, key := range expired {
		e.DelV4Session(key)
	}
	logger.Logger.Info("[管控] 删除过期的Executor", zap.Int("v4", expiredCount))
	return count, bandwidth, expired
}

func (e *Sessions) AddV6Session(uid string, bandwidth int64) {
	e.sessionsV6.Set(uid, &Session{
		uid:       uid,
		timestamp: time.Now().Unix(),
		bandwidth: uint64(bandwidth),
	})
}

func (e *Sessions) UpdateV6Session(uid string) {
	session := e.GetV6Session(uid)
	if session == nil {
		return
	}
	session.timestamp = time.Now().Unix()
}

func (e *Sessions) GetV6Session(uid string) *Session {
	val, exist := e.sessionsV6.Get(uid)
	if !exist {
		return nil
	}
	return val.(*Session)
}

func (e *Sessions) DelV6Session(uid string) {
	e.sessionsV6.Remove(uid)
}

func (e *Sessions) ExistV6Session(uid string) bool {
	return e.sessionsV6.Has(uid)
}

func (e *Sessions) GetOnlineV6Stat() (int64, uint64, []string) {
	var (
		count        int64
		bandwidth    uint64
		expired      []string
		expiredCount int
	)
	now := time.Now().Unix()
	e.sessionsV6.IterCb(func(key string, value any) {
		session := value.(*Session)
		if now-session.timestamp < config.AppConfig().Dy.AgentInterval+60 {
			count++
			bandwidth += session.bandwidth
		} else {
			if expiredCount < config.AppConfig().Dy.ExpiredLimit {
				expired = append(expired, key)
			}
			expiredCount++
		}
	})
	for _, key := range expired {
		e.DelV6Session(key)
	}
	logger.Logger.Info("[管控] 删除过期的Executor", zap.Int("v6", expiredCount))
	return count, bandwidth, expired
}
